package org.dding.msc.service.management;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.dding.core.log.ILogger;
import org.dding.core.log.LoggerFactory;
import org.dding.core.manager.IServiceManager;
import org.dding.msc.service.DependencyInfo;
import org.dding.msc.service.ServiceController;
import org.dding.msc.service.ServiceController.Mode;
import org.dding.msc.service.ServiceName;
import org.dding.msc.service.ServiceState;
import org.dding.msc.service.ServiceStateInfo;
import org.dding.msc.service.ServiceStateManager;

public class ServiceContainer implements ServiceContainerMBean {

	IServiceManager serviceManager;
	private ILogger logger = LoggerFactory.getLogger(getClass());

	public ServiceContainer(IServiceManager serviceManager) {
		this.serviceManager = serviceManager;
	}

	public ServiceStatus getServiceStatus(final String name) {
		final ServiceController<?> instance = serviceManager.getService(name);
		if (instance != null) {
			return instance.getStatus();
		}
		return null;
	}

	public List<String> queryServiceNames() {
		final List<ServiceName> names = serviceManager.getServiceNames();
		final ArrayList<String> list = new ArrayList<String>(names.size());
		for (ServiceName serviceName : names) {
			list.add(serviceName.getCanonicalName());
		}
		Collections.sort(list);
		return list;
	}

	public List<ServiceStatus> queryServiceStatuses() {
		final List<ServiceName> names = serviceManager.getServiceNames();
		final ArrayList<ServiceStatus> list = new ArrayList<ServiceStatus>(
				names.size());
		for (ServiceName name : names) {
			final ServiceController<?> instance = serviceManager
					.getService(name.getSimpleName());
			if (instance != null)
				list.add(instance.getStatus());
		}
		Collections.sort(list, new Comparator<ServiceStatus>() {
			public int compare(final ServiceStatus o1, final ServiceStatus o2) {
				return o1.getServiceName().compareTo(o2.getServiceName());
			}
		});
		return list;
	}

	public void setServiceMode(final String name, final String mode) {
		final ServiceController<?> instance = serviceManager.getService(name);
		if (instance != null) {
			instance.setMode(Mode.valueOf(mode.toUpperCase(Locale.US)));
		}
	}

	public void dumpServices() {
		dumpServices(System.out);
	}

	public void dumpServices(PrintStream out) {
		logger.debug("dump all Service");
		final List<ServiceName> registry = serviceManager.getServiceNames();
		if (registry.isEmpty()) {
			out.printf("(Registried service is empty)\n");
		} else {
			int i = 0;
			Set<ServiceController<?>> set = new HashSet<ServiceController<?>>();
			for (ServiceName name : registry) {
				final ServiceController<?> instance = serviceManager
						.getService(name.getSimpleName());
				if (instance != null) {
					if (instance != null && set.add(instance)) {
						i++;
						out.printf("%s\n", instance.getStatus());
					}
				}
			}
			out.printf("%s services displayed\n", Integer.valueOf(i));
		}
	}

	public void dumpServicesState() {
		ServiceStateManager stateManager = ServiceStateManager.getInstance();
		for (Map.Entry<ServiceName, ServiceState> entry : stateManager
				.getServiceStates().entrySet()) {
			PrintStream out = System.out;
			out.printf("Services for %s:\n", entry.getKey());
			ServiceState state = entry.getValue();
			handlerState(state, out);
		}
	}

	private void handlerState(ServiceState state, PrintStream out) {
		Collection<DependencyInfo> depends = state.getIDepends();
		if (depends != null && depends.size() != 0) {
			out.printf("\t I Depends:%s\n", depends.toArray());
		}

		Collection<ServiceStateInfo> stateInfo = state.getServiceStates();
		if (stateInfo != null && stateInfo.size() != 0) {
			for (ServiceStateInfo info : stateInfo) {
				out.printf("\t state:%s\n" + info.getState());
				out.printf("\t message:%s\n" + info.getMessage());
			}
		}
	}

	public String dumpServicesToString() {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		PrintStream ps = null;
		try {
			ps = new PrintStream(baos, false, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			throw new IllegalStateException(e);
		}
		dumpServices(ps);
		ps.flush();
		try {
			return new String(baos.toByteArray(), "UTF-8");
		} catch (UnsupportedEncodingException e) {
			throw new IllegalStateException(e);
		}
	}

	@Override
	public boolean stopService(String serviceName) {
		return serviceManager.stopService(serviceName);
	}

	@Override
	public boolean startService(String serviceName) {
		return serviceManager.startService(serviceName);
	}

	@Override
	public boolean removeService(String serviceName) {
		return serviceManager.removeService(serviceName);
	}

	@Override
	public boolean waitService(String serviceName) {
		return serviceManager.waitService(serviceName);
	}
}
